package com.salinity.kun.algorithm;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import com.salinity.kun.model.StationDateData;

/**
 * 非等间距数据的傅里叶展开
 * 
 * @author Administrator
 *
 */
public class FourierSeriesNotEqual {

	private double DeltaT; // 采样时间间隔
	private Double[] Ft = null; // 采样数据
	private int SeriesCount;// 傅里叶分级级数，默认设为T0/DeltaT/2
	private double T0; // 周期
	private double W; // 波形的角速度，值为2PI/T0
	private List<StationDateData> dataList;
	private double[] dtArr = null;
	private double[] a;
	private double[] b;

	public FourierSeriesNotEqual(List<StationDateData> dataList) throws ParseException {
		this.dataList = dataList;
		init();
	}

	public void init() throws ParseException {

		if (dtArr == null || Ft == null) {
			DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			DecimalFormat def = new DecimalFormat("#.####");
			StationDateData d1 = null, d2 = null;
			Date date1, date2;
			long dtl = 0, nh = 60 * 60 * 1000;
			double dt = 0.0;
			dtArr = new double[dataList.size()];
			Ft = new Double[dataList.size()];
			dtArr[0] = 0.0;
			Ft[0] = dataList.get(0).getValue();
			for (int i = 1; i < dataList.size(); i++) {
				d1 = dataList.get(i - 1);
				d2 = dataList.get(i);
				date1 = sdf.parse(d1.getDate());
				date2 = sdf.parse(d2.getDate());
				dtl = date2.getTime() - date1.getTime();
				dt = dtl * 1.0 / nh;
				dtArr[i] = Double.parseDouble(def.format(dtArr[i - 1] + dt));
				Ft[i] = dataList.get(i).getValue();
			}
			T0 = dtArr[dtArr.length - 1];
			W = 2 * Math.PI / T0;
			SeriesCount = 300;
		}
	}

	public double get_a(int index) throws ParseException {
		init();
		double a_i = 0.0;
		double up, down;
		int len = dataList.size();

		double T = T0;
		double T1 = T / 2f;
		double t0 = -T1;
		double t1 = 0.0;
		// 梯形面积求和

		for (int i = 1; i < len; i++) {
			t0 = -T1 + i * dtArr[i - 1];
			t1 = -T1 + i * dtArr[i];
			up = Ft[i] * Math.cos(index * W * t0);
			down = Ft[i] * Math.cos(index * W * t1);
			a_i += 0.5 * (up + down) * (dtArr[i] - dtArr[i - 1]);
		}
		return 2 * a_i / T;
	}

	public double get_b(int index) throws ParseException {

		double b_i = 0.0;
		double up, down;
		int len = dataList.size();

		double T = T0;
		double T1 = T / 2f;
		double t0 = -T1;
		double t1 = 0.0;
		// 梯形面积求和

		for (int i = 1; i < len; i++) {
			t0 = -T1 + i * dtArr[i - 1];
			t1 = -T1 + i * dtArr[i];
			up = Ft[i] * Math.sin(index * W * t0);
			down = Ft[i] * Math.sin(index * W * t1);
			b_i += 0.5 * (up + down) * (dtArr[i] - dtArr[i - 1]);
		}
		return 2 * b_i / T;
	}

	public double[] get_a() throws ParseException {
		if (a == null) {
			a = new double[SeriesCount + 1];
			for (int i = 0; i < SeriesCount + 1; i++) {
				a[i] = get_a(i);
			}
		}
		return a;
	}
	
	public double[] get_b() throws ParseException {
		if (b == null) {
			b = new double[SeriesCount+1];
			for (int i = 0; i < SeriesCount+1; i++) {
				b[i] = get_b(i);
			}
		}
		return b;
	}

	public double getFtCalByTime(double t) throws ParseException {

		if (a == null) {
			a = get_a();
		}
		if (b == null) {
			b = get_b();
		}
		double ft = 0.0;
		ft += a[0] / 2f;

		double T = T0;
		W = 2 * Math.PI / T;
		double t0 = t;
		for (int i = 1; i < SeriesCount + 1; i++) {
			ft += a[i] * Math.cos(i * W * t0) + b[i] * Math.sin(i * W * t0);
		}
		return ft;
	}
}
